﻿/*
 * Author: Trevor Vallender <tsv@tsv.me.uk>
 * Licence: Ms-PL
 */

using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Media.Imaging;

namespace PhotoOrg
{
    public class PhotoOrganiser
    {
        /// <summary>
        /// Constructor to convert strings to DirectoryInfo objects
        /// </summary>
        /// <param name="dir">Directory to sort</param>
        /// <param name="dest">Directory to move to</param>
        /// <param name="recursive">Traverse subdirectories?</param>
        public void Organise(string dir, string dest, bool recursive)
        {
            DirectoryInfo d;
            if (Directory.Exists(dir))
            {
                d = new DirectoryInfo(dir);
            }
            else
            {
                DirectoryNotFoundException ex = new DirectoryNotFoundException();
                throw ex;
            }

            DirectoryInfo desti;
            if (Directory.Exists(dest))
            {
                desti = new DirectoryInfo(dest);
            }
            else
            {
                DirectoryNotFoundException ex = new DirectoryNotFoundException();
                throw ex;
            }

            this.Organise(d, desti, recursive);
        }

        /// <summary>
        /// Calls SortFile() on all *.jpe?gs
        /// </summary>
        /// <param name="d">Directory to sort from</param>
        /// <param name="dest">Directory to sort to</param>
        /// <param name="recursive">Should sorting be recursive?</param>
        public void Organise(DirectoryInfo d, DirectoryInfo dest, bool recursive)
        {
            foreach (FileInfo f in d.GetFiles())
            {
                switch (f.Extension.ToString().ToLower())
                {
                    case ".jpg":
                    case ".jpeg":
                        SortFile(f, dest);
                        break;
                }
            }

            if (recursive)
            {
                foreach (DirectoryInfo s in d.GetDirectories())
                {
                    Organise(s, dest, recursive);
                }
            }
        }

        /// <summary>
        /// Retrieves date from photo's metadata
        /// </summary>
        /// <param name="f">Which file's date to retrieve</param>
        /// <returns></returns>
        public DateTime GetDate(FileInfo f)
        {
            FileStream fs = new FileStream(f.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);
            BitmapSource img = BitmapFrame.Create(fs);
            BitmapMetadata md = (BitmapMetadata)img.Metadata;
            string date = md.DateTaken;

            int day, month, year, hour, minute, second;
            DateTime dateTime = new DateTime();
            string regex = @"(?<day>\d\d)/(?<month>\d\d)/(?<year>\d\d\d\d) (?<hour>\d\d):(?<minute>\d\d):(?<second>\d\d)";
            Regex r = new Regex(regex);
            Match m = r.Match(date);
            if (m.Success)
            {
                day = Convert.ToInt32(m.Groups["day"].Value);
                month = Convert.ToInt32(m.Groups["month"].Value);
                year = Convert.ToInt32(m.Groups["year"].Value);
                hour = Convert.ToInt32(m.Groups["hour"].Value);
                minute = Convert.ToInt32(m.Groups["minute"].Value);
                second = Convert.ToInt32(m.Groups["second"].Value);
                Console.Write("{0}/{1}/{2} {3}:{4}:{5}", day, month, year, hour, minute, second);
                dateTime = new DateTime(year, month, day, hour, minute, second);
            }
            else
            {
                Console.WriteLine("Couldn't get metadata");
            }

            return dateTime;
        }

        /// <summary>
        /// Copies file to new location, with date-based renaming
        /// </summary>
        /// <param name="f">File to copy</param>
        /// <param name="dest">Where to copy to</param>
        public void SortFile(FileInfo f, DirectoryInfo dest)
        {
            DateTime date = GetDate(f);

            int[] dateTime = new int[6];
            dateTime[0] = date.Year;
            dateTime[1] = date.Month;
            dateTime[2] = date.Day;
            dateTime[3] = date.Hour;
            dateTime[4] = date.Minute;
            dateTime[5] = date.Second;
            string[] dateTimeStr = new string[6];
            for (int i = 0; i < 6; i++)
            {
                if (dateTime[i] < 10)
                {
                    dateTimeStr[i] = "0" + dateTime[i].ToString();
                }
                else
                {
                    dateTimeStr[i] = dateTime[i].ToString();
                }
            }

            string newPath;
            newPath = dest.FullName;
            newPath += "\\" + dateTimeStr[0];
            newPath += "\\" + dateTimeStr[1];
            newPath += "\\" + dateTimeStr[2];
            string newName;
            newName = dateTimeStr[3];
            newName += dateTimeStr[4];
            newName += dateTimeStr[5];
            newName += ".jpg";

            DirectoryInfo d = new DirectoryInfo(newPath);
            if (!d.Exists)
            {
                d.Create();
            }
            newPath += "\\" + newName;

            // Create .0.jpg, .1.jpg naming if files exist already
            FileInfo fi = new FileInfo(newPath); // Destination file
            FileInfo fiNew = new FileInfo(newPath);
            if (fi.Exists)
            {
                string testPath = "";
                string newTestPath = "";
                Boolean done = false;
                for (int i = 0; !done; i++)
                {
                    testPath = "";
                    newTestPath = "";
                    testPath = fi.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(fi.FullName);
                    newTestPath = testPath + "." + i + fi.Extension;
                    fiNew = new FileInfo(newTestPath);
                    if (!fiNew.Exists)
                    {
                        done = true;
                    }
                }
            }

            System.IO.File.Copy(f.FullName, fiNew.FullName);
        }
    }
}
